﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace Lib.Scripts.NetWork
{
   public class TooleMessage
    {

         #region 属性

    public byte[] Content { get; set; }
    public byte Flag { get; set; }
    public int Size { get; set; }
    public int CommandSize { get; set; }
    public byte Class { get; set; }

    #endregion

    public TooleMessage()
    {
    }

    public TooleMessage(byte @class, byte flag, int commandSize, byte[] content)
    {
        Class = @class;
        Flag = flag;
        Size = content.Length;
        CommandSize = commandSize;
        Content = content;
    }

    public byte[] ToBytes()
    {
        byte[] bytes;
        using (var mem = new MemoryStream())
        {
            var writer = new BinaryWriter(mem);
            writer.Write(Class);
            writer.Write(Flag);
            writer.Write(Size);
            writer.Write(CommandSize);
            if (Size > 0)
            {
                writer.Write(Content);
            }
            bytes = mem.ToArray();
            writer.Close();
        }
        return bytes;
    }

    public TooleMessage FromBytes(byte[] buffer)
    {
        var message = new TooleMessage();
        using (var mem = new MemoryStream(buffer))
        {
            var reader = new BinaryReader(mem);
            message.Class = reader.ReadByte();
            message.Flag = reader.ReadByte();
            message.Size = reader.ReadInt32();
            message.CommandSize = reader.ReadInt32();
            if (message.Size > 0)
            {
                message.Content = reader.ReadBytes(message.Size);
            }
            reader.Close();
        }
        return message;
    }
    }

   public class TooleMessageStream
   {
       private byte[] _buffer;
       private int _position;
       private int _length;
       private int _capacity;


       public TooleMessageStream()
       {
           _buffer = new byte[0];
           _position = 0;
           _length = 0;
           _capacity = 0;

       }

       /// <summary>
       /// 读取byte占的长度
       /// </summary>
       /// <returns></returns>
       private byte ReadByte()
       {
           return (byte)(_position >= _length ? 0 : _buffer[_position++]);
       }
       /// <summary>
       /// 读取int 占的长度
       /// </summary>
       /// <returns></returns>
       private int ReadInt()
       {
           var num = _position += 4;
           if (num <= _length)
           {
               return (((_buffer[num - 4] | (_buffer[num - 3] << 8)) | (_buffer[num - 2] << 0x10)) |
                       (_buffer[num - 1] << 0x18));//位加操作 其中| 在位运算中表示连接
           }
           _position = _length;
           return -1;
       }

       /// <summary>
       ///  根据size获取消息数据
       /// </summary>
       /// <param name="count"></param>
       /// <returns></returns>
       private byte[] ReadBytes(int count)
       {
           var num = _length - _position;
           if (num > count)
           {
               num = count;
           }
           if (num <= 0)
           {
               return null;
           }
           var buffer = new byte[num];
           if (num <= 8)
           {
               var num2 = num;
               while (--num2 >= 0)
               {
                   buffer[num2] = _buffer[_position + num2];
               }
           }
           else
           {
               Buffer.BlockCopy(_buffer, _position, buffer, 0, num);
           }
           _position += num;
           return buffer;
       }

       /// <summary>
       /// 读取一整个数据包，并将其移除
       /// </summary>
       /// <param name="message"></param>
       /// <returns></returns>
       public bool Read(out TooleMessage message)
       {
           message = null;
           _position = 0;
           if (_length <= 10)
           {
               return false;
           }
           message = new TooleMessage { Class = ReadByte(), Flag = ReadByte(), Size = ReadInt(), CommandSize = ReadInt() };
           if (message.Size <= 0 || message.Size <= _length - _position)
           {
               if (message.Size > 0)
               {
                   message.Content = ReadBytes(message.Size);
               }
               Remove(message.Size + 10);
               return true;
           }
           message = null;
           return false;
       }

       /// <summary>
       /// 根据原有的长度加上新读来的长度创建缓冲区
       /// </summary>
       /// <param name="value"></param>
       private void EnsureCapacity(int value)
       {
           if (value <= _capacity)
               return;
           var num1 = value;
           if (num1 < 0x100)// int 256
               num1 = 0x100;
           if (num1 < (_capacity * 2))
               num1 = _capacity * 2;
           var buffer1 = new byte[num1];
           if (_length > 0)
               Buffer.BlockCopy(_buffer, 0, buffer1, 0, _length);
           _buffer = buffer1;
           _capacity = num1;
       }


       /// <summary>
       /// 将新读来的消息写入缓冲区
       /// </summary>
       /// <param name="buffer"></param>
       /// <param name="offset"></param>
       /// <param name="count"></param>
       public void Write(byte[] buffer, int offset, int count)
       {
           if (buffer.Length - offset < count)
           {
               count = buffer.Length - offset;
           }
           EnsureCapacity(_length + count);
           Array.Clear(_buffer, _length, _capacity - _length);
           Buffer.BlockCopy(buffer, offset, _buffer, _length, count);
           _length += count;
       }

       /// <summary>
       /// 移除已读的消息
       /// </summary>
       /// <param name="count"></param>
       private void Remove(int count)
       {
           if (_length >= count)
           {
               Buffer.BlockCopy(_buffer, count, _buffer, 0, _length - count);
               _length -= count;
               Array.Clear(_buffer, _length, _capacity - _length);
           }
           else
           {
               _length = 0;
               Array.Clear(_buffer, 0, _capacity);
           }
       }
   }

}
